//先定义三种状态
const fulfilled = "fulfilled"; //成功
const rejected = "rejected"; // 失败
const pending = "pending"; // 进行中

//判断是否是promise
function isPromise(fn) {
  if ((typeof fn === "object" && fn !== null) || typeof fn === "function") {
    return fn.then && typeof fn.then === "function";
  }
  return false;
}

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    // 如果promise2 和x 相等，那么抛出类型错误
    throw new Error("类型错误");
  }
  //判断x是一个普通值还是一个promise
  if ((typeof x === "object" && x !== null) || typeof x === "function") {
    // console.log('x:',  x.then());
    try {
      let then = x.then;
      //说明x是一个promise
      if (then && typeof then === "function") {
        //执行then方法，this指向X ，成功的回调函数有可能又是一个promise
        then.call(
          x,
          (y) => {
            // y 有可能也是一个promise对象，所以接着处理
            resolvePromise(promise2, y, resolve, reject);
          },
          (r) => {
            reject(r);
          }
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      reject(e);
    }
  } else {
    resolve(x);
  }
}

class Promise {
  constructor(executor) {
    //每一个promise对象，最开始的状态肯定是pending
    this.status = pending;
    this.value = ""; //存储成功的原因
    this.reason = ""; //存储失败的原因

    this.successFn = []; // 保存成功的回调
    this.failFn = []; //保存失败的回调

    // 调用resolve 方法会把当前promise对象的状态变为fulfilled，并且会执行then方法的回调
    let resolve = (value) => {
      if (this.status === pending) {
        this.status = fulfilled; //改变状态
        this.value = value; // 保存成功的值
        //改变状态了 ，去执行then方法中成功的回调函数
        if (this.successFn.length > 0) {
          this.successFn.forEach((fn) => fn(this.value));
        }
      }
    };
    // 调用reject 方法会把当前promise对象的状态变为rejected，并且会执行catch方法的回调
    let reject = (reason) => {
      if (this.status === pending) {
        this.status = rejected; // 改变状态
        this.reason = reason; // 保存失败的值
        if (this.failFn.length > 0) {
          this.failFn.forEach((fn) => fn(this.reason));
        }
      }
    };
    // 立即执行，为了防止报错，我们tryCatch一下，如果报错了，就把promise的状态改变为失败
    try {
      executor(resolve, reject);
    } catch (e) {
      if (this.status === pending) {
        this.status = rejected;
        this.reason = e;
      }
    }
  }
  // then方法会接受两个参数，第一个参数是resolved状态的回调函数，第二个参数是rejected状态的回调函数，它们都是可选的。
  then(onFulfilled, onRejected) {
    //参数的可选
    onFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (val) => val;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (err) => {
            throw err;
          };
    let promise2 = new Promise((resolve, reject) => {
      // 由于我们调用then方法的时候，promise对象的状态可能还是pending状态，这个时候我们就先要保存他的成功或者失败的回调，然后等状态改变了再去调用
      if (this.status === pending) {
        onFulfilled &&
          this.successFn.push(() => {
            try {
              let x = onFulfilled(this.value);
              // x这个返回值也有可能是一个promise对象，所以需要resolvePromise这个处理程序去进行比对一下
              // 判断x和promise2是不是同一个promise
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        onRejected &&
          this.failFn.push(() => {
            try {
              let x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
      }

      //如果已经成功了
      if (this.status === fulfilled) {
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
      //如果已经失败了
      if (this.status === rejected) {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
    });

    return promise2;
  }
  static race(args) {
    return new Promise((resolve, reject) => {
      for (let i = 0; i < args.length; i++) {
        if (isPromise(args[i])) {
          args[i].then(
            (res) => {
              // 任何一个promise的状态改变了，我们就把外层的promise状态改变，就只会得到第一个状态改变了的promise的返回值
              resolve(res);
            },
            (err) => {
              reject(err);
            }
          );
        } else {
          //如果不是promise 直接成功
          resolve(args[i]);
        }
      }
    });
  }

  static resolve(value) {
    return new Promise((res, rej) => {
      // 直接调用resolve,将状态变为成功态
      res(value);
    });
  }
  static reject(err) {
    return new Promise((res, rej) => {
      // 直接调用rejext,将状态变为失败态
      rej(err);
    });
  }
  finally(callback) {
    callback(); // 直接执行
    // 调用then方法
    return this.then(
      (res) => {
        return this.resolve(res);
      },
      (err) => {
        return this.reject(err);
      }
    );
  }
}
//promise的all方法
Promise.all = function(promises) {
  // 返回一个新的promise
  return new Promise((resolve, reject) => {
    let arr = []; //返回的数组
    let i = 0;
    let processData = (index, data) => {
      arr[index] = data;
      if (++i === promises.length) {
        // 如果当前i等于传入数组的长度，那么说明所有的promise项都已经执行完成了
        resolve(arr);
      }
    };

    for (let i = 0; i < promises.length; i++) {
      let current = promises[i]; //获得每一项
      if (isPromise(current)) {
        //如果是promise，那么等他的then方法执行的时候将结果放入到新的数组中去
        current.then((data) => {
          // 按照传入数组的位置将结果放入到新的数组中
          processData(i, data);
        }, reject);
      } else {
        processData(i, current);
      }
    }
  });
};

export default Promise;
